Amazon EFSのメタデータの読み書きサイズが気になったので検証してみた
ls や rsync するときにどのぐらいメタデータの読み込みが発生するのか気になる
こんにちは、のんピ(@non____97)です。
皆さんは「Amazon EFSファイルシステム上の領域でls や rsync するときにメタデータのどのぐらい読み込まれるのか気になる」と思ったことはありますか? 私はあります。
2022年のre:Invent期間中にEFSにElastic Throughputモードが追加されました。
こちらのスループットモードは転送量に基づいて従量課金されます。東京リージョンの価格は以下の通りです。
- Elastic スループットリクエスト - Data and Metadata 読み取り (転送 1 GB あたり) :
0.04USD
- Elastic スループットリクエスト - Data and Metadata 書き込み (転送 1 GBあたり) :
0.07USD
ここでData and Metadata
のMetadata
が実際どのぐらいの量になるのか気になりました。
lsやrsyncなど通常利用でファイルにアクセスしたときに、発生するメタデータのIOが大きいのであれば気を使いたいところです。
定常的に読み書きが多い環境において、Elastic Throughputモードを使用すると想定よりも課金が発生しがちです。
実際にlsやrsyncをしてどのぐらいメタデータの読み込みが発生するのか確認します。
いきなりまとめ
- 大量のファイルやディレクトリがある環境において、rsyncやfindなどファイル走査を行うような操作を頻繁に行うのは注意しよう
- ファイルの読み込みをすると、1ファイルあたり4KiBのメタデータのIOが発生する
- データの読み書きは32KiB単位で計算される
- ファイルの大小でメタデータのサイズは変わらない
検証環境
検証環境は以下の通りです。
EC2インスタンスからEFSファイルシステムをNFSでマウントしているだけです。
検証環境はAWS CDKでデプロイしました。使用したコードは以下リポジトリに保存しています。
12,500個のファイルを作成したときのメトリクス
まず、検証用に12,500個のファイルを作成します。
# マウントポイントの作成 $ sudo mkdir -p /mnt/efs # EFSのマウント $ sudo mount -t nfs fs-0af7d4648f5d78663.efs.us-east-1.amazonaws.com:/ /mnt/efs # NFSv4でマウントできていることを確認 $ df -hT -t nfs4 Filesystem Type Size Used Avail Use% Mounted on fs-0af7d4648f5d78663.efs.us-east-1.amazonaws.com:/ nfs4 8.0E 0 8.0E 0% /mnt/efs # 5つのディレクトリに5つのサブディレクトリを作成し、各サブディレクトリに512KiBのファイルを500個作成する $ cnt=0 $ for i in {1..5}; do sudo mkdir "/mnt/efs/dir_${i}" for j in {1..5}; do sudo mkdir "/mnt/efs/dir_${i}/dir_${j}" for k in {1..500}; do sudo dd if=/dev/zero of=/mnt/efs/dir_${i}/dir_${j}/file_${k} bs=512K count=1 status=none echo $((cnt++)) done done done
20分ほどで作成完了しました。
CloudWatchメトリクスでEFSファイルシステムのメトリクスを確認しましょう。
EFSファイルシステムのCloudWatchメトリクスは以下公式ドキュメントにまとまっています。
1分間の平均のメトリクスは以下の通りです。
MetadataIOBytes
とMetadataWriteIOBytes
、MetadataReadIOBytes
はいずれも4,096
でした。統計を平均
にしているのでMetadataIOBytes
はMetadataWriteIOBytes
とMetadataReadIOBytes
の合計の平均だと考えます。
また、TotalIOBytes
とMeteredIOBytes
のサイズが一致していました。それぞれ以下のように計算されます。
TotalIOBytes
: データ読み取り + データ書き込み + メタデータ操作MeteredIOBytes
: データ読み取り × 1/3 + データ書き込み + メタデータ操作
2つのメトリクスの数値が同じということはデータ読み取りは発生していないということですね。
次に1分間の合計メトリクスです。
毎分おおよそ354MBの書き込みが発生しているようです。
MetadataWriteIOBytes
とMetadataReadIOBytes
はどちらも2.6MBで、MetadataIOBytes
は5.2MBとなっています。MetadataIOBytes
はMetadataWriteIOBytes
とMetadataReadIOBytes
の合計であることが分かりますね。
12,500個のファイルをrsyncしたときのメトリクス
12,500個のファイルをEFSファイルシステムからEC2インスタンスのEBSボリュームの領域にrsyncします。
$ rsync -a --stats /mnt/efs/ /home/ec2-user/ Number of files: 12,531 (reg: 12,500, dir: 31) Number of created files: 12,530 (reg: 12,500, dir: 30) Number of deleted files: 0 Number of regular files transferred: 12,500 Total file size: 6,553,600,000 bytes Total transferred file size: 6,553,600,000 bytes Literal data: 6,553,600,000 bytes Matched data: 0 bytes File list size: 0 File list generation time: 0.039 seconds File list transfer time: 0.000 seconds Total bytes sent: 6,555,918,383 Total bytes received: 237,831 sent 6,555,918,383 bytes received 237,831 bytes 51,420,833.05 bytes/sec total size is 6,553,600,000 speedup is 1.00
2分ほどで完了しました。
1分間の合計メトリクスは以下の通りです。
MetadataIOBytes
は常に約50MBでした。ファイル作成時の1/10の時間で完了して、MetadataIOBytes
もファイル作成時の1/10のサイズなので、1ファイルあたりのメタデータサイズは変わらなさそうです。
また、EFSファイルシステムrsyncの送信元ですがMetadataWriteIOBytes
も発生しています。
1分間の平均メトリクスは以下の通りです。
こちらはファイル作成時のメトリクスとほとんど変わりありません。
もう一度rsyncを実行します。
$ rsync -a --stats /mnt/efs/ /home/ec2-user/ Number of files: 12,531 (reg: 12,500, dir: 31) Number of created files: 0 Number of deleted files: 0 Number of regular files transferred: 0 Total file size: 6,553,600,000 bytes Total transferred file size: 0 bytes Literal data: 0 bytes Matched data: 0 bytes File list size: 0 File list generation time: 0.003 seconds File list transfer time: 0.000 seconds Total bytes sent: 230,834 Total bytes received: 90 sent 230,834 bytes received 90 bytes 65,978.29 bytes/sec total size is 6,553,600,000 speedup is 28,379.90
5秒ほどで完了しました。
そのときの1分間の合計メトリクスは以下の通りです。
IOBytes
のメトリクスが全て21.5MBでした。つまりはメタデータの読み込みで21.5MBの転送が発生していることになります。
もう何回か試してみます。
3回ほど試しましたがいずれもIOBytes
のメトリクスの1分間の合計はいずれも51MBでした。
$ rsync -avh --stats /mnt/efs/ /home/ec2-user/ sending incremental file list Number of files: 12,531 (reg: 12,500, dir: 31) Number of created files: 0 Number of deleted files: 0 Number of regular files transferred: 0 Total file size: 6.55G bytes Total transferred file size: 0 bytes Literal data: 0 bytes Matched data: 0 bytes File list size: 0 File list generation time: 0.004 seconds File list transfer time: 0.000 seconds Total bytes sent: 230.83K Total bytes received: 90 sent 230.83K bytes received 90 bytes 35.53K bytes/sec total size is 6.55G speedup is 28,379.90
51MBをファイルの総数12,500で割ると4.17KBです。
AWS公式ドキュメントにはメタデータは2KiBという記載がありました。
Amazon EFS システムで顧客に表示されるオブジェクトには、通常のファイル、ディレクトリ、シンボリックリンク、特殊ファイル (FIFO とソケット) があります。これらの各オブジェクトは、メタデータ (inode) の 2 キビバイト (KiB) と 4 KiB のデータの 1 つ以上の増分に対して計測されます。次の一覧は、さまざまなタイプのファイルシステムオブジェクトの測定データサイズの説明です。
計測: Amazon EFS がファイルシステムとオブジェクトサイズをレポートする仕組み - Amazon Elastic File System
一方で、同じドキュメントにメタデータのIOは4KiB単位で計算されると記載がありました。
エラスティックスループットの測定
あるファイルシステムで Elastic Throughput が有効になっている場合は、ファイルシステムから読み書きされたメタデータとデータの量に対してのみ支払いが発生します。エラスティックスループットモードを使用する Amazon EFS ファイルシステムでは、メタデータの読み取りをデータ読み取りオペレーションとして、メタデータの書き込みをメタデータの書き込みオペレーションとして計測し、請求します。
Amazon EFS ファイルシステムから読み書きされるメタデータは、4 KiB 単位で測定されます。Amazon EFS ファイルシステムから読み書きされたデータは、32 KiB 単位で計測されます。
EFSファイルシステム上で保存されるメタデータのサイズとしては1ファイルあたり2KiBだが、そのメタデータの読み書きをする場合は4KiB単位で行われるということでしょうか。
1ファイルあたりのサイズが変わった場合のメタデータの読みこみ量の確認
「メタデータの読み込み量が51MBとなったのは、12,500個のファイルが全て512KBだから」という可能性も0ではないかと思うので、一部ファイルのサイズを2MBにした上でrsyncします。
12,500個のファイルのうち、2,500個のファイルを2MBに書き換えます。
$ cnt=0 $ for i in {1..1}; do for j in {1..5}; do for k in {1..500}; do sudo dd if=/dev/zero of=/mnt/efs/dir_${i}/dir_${j}/file_${k} bs=2M count=1 status=none echo $((cnt++)) done done done
5分ほどで完了しました。
rsyncを行います。
$ rsync -av --stats /mnt/efs/ /home/ec2-user/ sending incremental file list dir_1/dir_1/file_1 dir_1/dir_1/file_10 dir_1/dir_1/file_100 dir_1/dir_1/file_101 dir_1/dir_1/file_102 dir_1/dir_1/file_103 dir_1/dir_1/file_104 dir_1/dir_1/file_105 dir_1/dir_1/file_106 dir_1/dir_1/file_107 dir_1/dir_1/file_108 dir_1/dir_1/file_109 . . (中略) . . dir_1/dir_5/file_95 dir_1/dir_5/file_96 dir_1/dir_5/file_97 dir_1/dir_5/file_98 dir_1/dir_5/file_99 Number of files: 12,531 (reg: 12,500, dir: 31) Number of created files: 0 Number of deleted files: 0 Number of regular files transferred: 2,500 Total file size: 10,485,760,000 bytes Total transferred file size: 5,242,880,000 bytes Literal data: 5,242,880,000 bytes Matched data: 0 bytes File list size: 0 File list generation time: 0.006 seconds File list transfer time: 0.000 seconds Total bytes sent: 5,244,488,334 Total bytes received: 47,602 sent 5,244,488,334 bytes received 47,602 bytes 62,808,813.60 bytes/sec total size is 10,485,760,000 speedup is 2.00
90秒ほどで完了しました。
このときの1分間の合計メトリクスは以下の通りです。
10,000個のファイルは変更がないので、全て差分となった初回転送と比べてMetadataWriteIOBytes
の量が少ないですね。
rsyncを何回か繰り返します。
いずれもMetadataReadIOBytes
は51MBほどでした。
ということでファイルの大小でメタデータのサイズは変わらないことを確認しました。
ls で一部ディレクトリにアクセスしたときのメタデータの読み込み量の確認
rsyncだけでなく、lsでファイルの一覧を表示したとき、どのぐらいのメタデータ読み込み量になるのか確認します。
1つのサブディレクトリについて、lsをします。
$ ls -l /mnt/efs/dir_1/dir_1/ | grep file | wc -l 500
そのときのメタデータ読み込み量は約2MBでした。
12,500個のファイルをrsyncで読み込んだときは51MBで、500個のファイルをlsで読み込んだときは2MBということで、読み込んだファイル数に比例して1/25となっています。
このことから、やはり1ファイルあたりのメタデータの読み込み量は4KiBとして計算されるようです。
そのため、1つのディレクトリに大量のファイルがある状態でlsを頻繁に叩く場合や、1分間隔など高頻度でrsyncをする場合、findをEFSファイルシステムのrootから行う場合などファイル走査の処理を行うと、メタデータの読み込みでそれなりに課金が発生しそうです。
仮に、こちらの検証環境において1分間隔で毎日rsyncを実行すると51MB × 60 min × 730 h / 1,024 = 2,181 GB
分もメタデータの読み込みのみで課金されます。
IOが一定なのであればプロビジョンドスループットモードを使う方がお安くなりそうです。
数バイトの小さいファイルが大量にある環境でも頻繁に読み書きを行うと想定よりも課金が発生しそう
Amazon EFSのメタデータの読み書きサイズが気になったので確認してみました。
メタデータは4KiB単位で、データは32KiB単位で計算されるというのがポイントですね。
データサイズが小さくとも大量のIOが発生すると、Elastic Throughputモードを使っているとそれなりの課金が発生しそうです。
「EFSには数GBしか保存していない」という場合でもファイルが大量にあれば、ファイル走査を頻繁に行うと予想外の課金となるかもしれません。
この記事が誰かの助けになれば幸いです。
以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!